package com.tender.desensitization;

import com.google.common.collect.Lists;
import com.tender.desensitization.filter.*;
import org.apache.commons.lang3.ClassUtils;
import org.springframework.core.ResolvableType;
import org.springframework.util.CollectionUtils;

import java.io.ObjectStreamField;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class FieldReflectUtils {

    private static final List<FieldFilter> excludeTypeFilters = Lists.newArrayList(
            new DateFieldFilter(),
            new StreamFieldFilter(),
            new NumberFieldFilter(),
            new ClassOrFieldIgnoreFilter(),
            new PrimitiveAndFinalFieldFilter());

    private static List<Class<?>> excludeClassList = Lists.newArrayList(
            ObjectStreamField.class,
            Object.class);

    public static List<Field> getAllFields(Class<?> clazz, List<FieldFilter> filterList) {
        if (excludeClassList.contains(clazz)) {
            return new ArrayList<>();
        }

        if (ClassUtils.isPrimitiveOrWrapper(clazz) || String.class == clazz) {
            return new ArrayList<>();
        }

        List<Field> fields = new ArrayList<>();

        // 循环获取当前类及其父类的所有字段
        while (clazz != null && clazz != Object.class) {
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                if (!CollectionUtils.isEmpty(filterList)) {
                    List<FieldFilter> collect = filterList.stream().filter(item -> item.isMatch(field))
                            .collect(Collectors.toList());
                    if (!CollectionUtils.isEmpty(collect)) {
                        continue;
                    }
                }
                fields.add(field);
            }
            clazz = clazz.getSuperclass();
        }

        return fields;
    }

    public static List<Field> getAllFields(Class<?> clazz) {
        return getAllFields(clazz, excludeTypeFilters);
    }

    /**
     * 判断是否是  Class<?> 类型
     *
     * @param field
     * @return
     */
    public static boolean isClassType(Field field) {
        // 获取字段的类型
        Class<?> fieldType = field.getType();

        // 检查字段类型是否是 Class 类
        return Class.class.isAssignableFrom(fieldType);
    }

    /**
     * 获取集合中的元素 泛型 Class<?>
     */
    public static Class<?> getGenericClassWithInCollection(Field field) {
        ResolvableType resolvableType = ResolvableType.forField(field);
        Class<?> resolve = resolvableType.resolve();
        Type type = resolvableType.getType();

        if (null != resolve) {
            while (null != resolve && resolve != type) {
                if (Map.class.isAssignableFrom(resolve)) {
                    resolvableType = resolvableType.getGeneric(1);
                    resolve = resolvableType.resolve();
                    type = resolvableType.getType();
                } else if (List.class.isAssignableFrom(resolve) || Set.class.isAssignableFrom(resolve)) {
                    resolvableType = resolvableType.getGeneric(0);
                    resolve = resolvableType.resolve();
                    type = resolvableType.getType();
                }
            }
        }

        return resolve;
    }

}
